package com.dtranx.tools.commons.util;

import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.SystemPropertyUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


/**
 * @ClassName ScanSupport
 * @Description TODO
 * @Date 2022/5/17 10:34
 * @Author ly
 */
public class ScanSupport implements ResourceLoaderAware {
    /**
     * Spring容器注入
     */
    private ResourceLoader resourceLoader;

    private ResourcePatternResolver resolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
    private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);

    /**
     * set注入对象
     */
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    /**
     * 利用spring提供的扫描包下面的类信息,再通过classfrom反射获得类信息
     * 
     * @param scanPath
     * @return
     * @throws IOException
     */
    public Set<Class<?>> doScan(String scanPath) throws Exception {
        Set<Class<?>> classes = new HashSet<Class<?>>();
        String packageSearchPath = "classpath*:"
                .concat(ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(scanPath))
                        .concat("/**/*.class"));
        Resource[] resources = resolver.getResources(packageSearchPath);
        MetadataReader metadataReader = null;
        for (Resource resource : resources) {
            if (resource.isReadable()) {
                metadataReader = metadataReaderFactory.getMetadataReader(resource);
                try {
                    // 当类型不是抽象类或接口在添加到集合
                    if (metadataReader.getClassMetadata().isConcrete()) {
                        classes.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
                    }
                } catch (Exception e) {
                    throw e;
                }
            }
        }
        return classes;
    }

    /**
     * 指定包下面的类信息
     * 
     * @return 多个类信息
     */
    public static Set<Class<?>> classInfos( String path) throws Exception {
        try {
            return new ScanSupport().doScan(path);
        } catch (Exception e) {
           throw e;
        }
    }

    /**
     * 验证父类
     * @param aClass
     * @param targetClass
     * @return
     */
    public static Boolean validate(Class<?> aClass,Class<?> targetClass){
        if(aClass == null){
            return false;
        }
        if(aClass.equals(targetClass)){
            return true;
        }
        if(aClass.equals(Object.class)){
            return false;
        }
        if(validate(aClass.getSuperclass(),targetClass)){
            return true;
        }
        Class<?>[] interfaces = aClass.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            if (validate(anInterface, targetClass)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取模型的字段
     * @param targetClass
     * @param fields
     */
    public static void getDeclaredFields(Class targetClass, List<Field> fields){
        if(targetClass == null || Object.class.equals(targetClass)){
            return;
        }
        Field[] declaredFields = targetClass.getDeclaredFields();
        if(declaredFields != null && declaredFields.length > 0){
            for(int i = 0;i<declaredFields.length;i++){
                fields.add(declaredFields[i]);
            }
        }
        getDeclaredFields(targetClass.getSuperclass(),fields);
    }

}